package com.ht.modules.system.controller;

import com.ht.entity.Result;
import com.ht.utils.DateUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.logging.log4j.util.Strings;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import static com.ht.utils.CloseStreamUtil.closeStream;

/**
 * 用户表 前端控制器
 */
@Slf4j
@RestController
@RequestMapping("/sys/common")
public class CommonController {

    @Value(value = "${jeecg.path.upload}")
    private String uploadpath;

    @GetMapping("/403")
    public Result<?> noAuth() {
        return Result.error("没有权限，请联系管理员授权");
    }

    /**
     * 上传文件
     * 上传后文件命名规则与/uploadFile不同
     */
    @PostMapping(value = "/upload")
    public Result<?> upload(HttpServletRequest request) {
        Result<?> result = new Result<>();
        FileOutputStream out = null;
        InputStream input = null;
        try {
            String ctxPath = uploadpath;
            String fileName;
            String bizPath = "files";
            String now = new SimpleDateFormat("yyyyMMdd").format(new Date());
            File file = new File(ctxPath + File.separator + bizPath + File.separator + now);
            if (!file.exists()) {
                // 创建文件根目录
                boolean r = file.mkdirs();
                if (!r) {
                    result.setMessage("创建文件根目录失败");
                    result.setSuccess(false);
                    return result;
                }
            }
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            MultipartFile mf = multipartRequest.getFile("file");
            if (mf == null) {
                result.setMessage("上传文件为空");
                result.setSuccess(false);
                return result;
            }
            // 获取文件名
            String orgName = mf.getOriginalFilename();
            if (orgName == null) {
                result.setMessage("获取文件名失败");
                result.setSuccess(false);
                return result;
            }
            String tempFileName = DateUtils.getDataString(DateUtils.yyyymmddhhmmss) + "_" + orgName.substring(0, orgName.indexOf("."));// 设置上传后文件名
            fileName = tempFileName + orgName.substring(orgName.lastIndexOf("."));
            String savePath = file.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            input = mf.getInputStream();
            out = new FileOutputStream(savefile);
            IOUtils.copy(input, out);
            String dbpath = bizPath + File.separator + now + File.separator + fileName;
            if (dbpath.contains("\\")) {
                dbpath = dbpath.replace("\\", "/");
            }
            result.setMessage(dbpath);
            result.setSuccess(true);
            out.close();
        } catch (IOException e) {
            result.setSuccess(false);
            result.setMessage(e.getMessage());
            log.error(e.getMessage(), e);
        } finally {
            closeStream(input, out);
        }
        return result;
    }

    /**
     * 仅能上传pdf文件
     */
    @PostMapping(value = "/uploadPdf")
    public Result<?> uploadPdf(HttpServletRequest request) {
        Result<?> result = new Result<>();
        FileOutputStream out = null;
        InputStream input = null;
        try {
            String ctxPath = uploadpath;
            String fileName;
            String bizPath = "files";
            String nowDay = new SimpleDateFormat("yyyyMMdd").format(new Date());
            File file = new File(ctxPath + File.separator + bizPath + File.separator + nowDay);
            if (!file.exists()) {
                boolean r = file.mkdirs();
                if (!r) {
                    result.setMessage("创建文件根目录失败");
                    result.setSuccess(false);
                    return result;
                }
            }
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            // 获取上传文件对象
            MultipartFile mf = multipartRequest.getFile("file");
            if (mf == null) {
                result.setMessage("上传文件为空");
                result.setSuccess(false);
                return result;
            }
            // 获取文件名
            String orgName = mf.getOriginalFilename();
            if (orgName == null) {
                result.setMessage("获取文件名失败");
                result.setSuccess(false);
                return result;
            }
            String substring = orgName.substring(orgName.lastIndexOf("."));
            if (!".pdf".equals(substring)) {
                throw new RuntimeException("合同附件只能是PDF格式文件");
            }
            String tempFileName = DateUtils.getDataString(DateUtils.yyyymmddhhmmss) + random(8);// 设置上传后文件名
            fileName = tempFileName + orgName.substring(orgName.lastIndexOf("."));
            String savePath = file.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            input = mf.getInputStream();
            out = new FileOutputStream(savefile);
            IOUtils.copy(input, out);
            String dbpath = bizPath + File.separator + nowDay + File.separator + fileName;
            if (dbpath.contains("\\")) {
                dbpath = dbpath.replace("\\", "/");
            }
            result.setMessage(dbpath);
            result.setSuccess(true);
        } catch (IOException e) {
            result.setSuccess(false);
            result.setMessage(e.getMessage());
            log.error(e.getMessage(), e);
        } finally {
            closeStream(input, out);
        }
        return result;
    }

    /**
     * 上传文件模板
     */
    @PostMapping(value = "/uploadFile")
    public Result<?> uploadFile(HttpServletRequest request) {
        Result<?> result = new Result<>();
        FileOutputStream out = null;
        InputStream input = null;
        try {
            String ctxPath = uploadpath;
            String fileName;
            String bizPath = "files";
            String nowDay = new SimpleDateFormat("yyyyMMdd").format(new Date());
            File file = new File(ctxPath + File.separator + bizPath + File.separator + nowDay);
            if (!file.exists()) {
                boolean r = file.mkdirs();
                if (!r) {
                    result.setMessage("创建文件根目录失败");
                    result.setSuccess(false);
                    return result;
                }
            }
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            MultipartFile mf = multipartRequest.getFile("file");
            if (mf == null) {
                result.setMessage("上传文件为空");
                result.setSuccess(false);
                return result;
            }
            // 获取文件名
            String orgName = mf.getOriginalFilename();
            if (orgName == null) {
                result.setMessage("获取文件名失败");
                result.setSuccess(false);
                return result;
            }
            fileName = orgName.substring(0, orgName.lastIndexOf("."))
                    + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
            String savePath = file.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            // FileCopyUtils.copy(mf.getBytes(), savefile);//文件太大时会导致内存溢出
            input = mf.getInputStream();
            out = new FileOutputStream(savefile);
            IOUtils.copy(input, out);
            String dbpath = bizPath + File.separator + nowDay + File.separator + fileName;
            if (dbpath.contains("\\")) {
                dbpath = dbpath.replace("\\", "/");
            }
            result.setMessage(dbpath);
            result.setSuccess(true);
        } catch (IOException e) {
            result.setSuccess(false);
            result.setMessage(e.getMessage());
            log.error(e.getMessage(), e);
        } finally {
            closeStream(input, out);
        }
        return result;
    }

    /**
     * 预览图片 或 pdf文件
     * 请求地址：<ConfigVo href="http://localhost:8080/common/view/{user/20190119/e1fe9925bc315c601b98eb1cb1349547719_1547866868179.jpg}">...</ConfigVo>
     */
    @GetMapping(value = "/view/**")
    public void view(HttpServletRequest request, HttpServletResponse response) {
        String imgPath = extractPathFromPattern(request);
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            imgPath = imgPath.replace("..", "");
            if (imgPath.endsWith(",")) {
                imgPath = imgPath.substring(0, imgPath.length() - 1);
            }
            String localPath = uploadpath;
            String imgurl = localPath + File.separator + imgPath;
            // 获取文件后缀
            String[] split = imgPath.split("\\.");
            String fileSuffix = split[split.length - 1];
            if ("pdf".equalsIgnoreCase(fileSuffix)) {
                response.setContentType("application/pdf");
            } else if ("jpg".equalsIgnoreCase(fileSuffix)
                    || "jpeg".equalsIgnoreCase(fileSuffix)
                    || "png".equalsIgnoreCase(fileSuffix)
                    || "bmp".equalsIgnoreCase(fileSuffix)) {
                response.setContentType("image/jpeg;charset=utf-8");
            }
            inputStream = new BufferedInputStream(Files.newInputStream(Paths.get(imgurl)));
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            log.error("预览图片失败" + e.getMessage());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 下载文件
     * 请求地址：<ConfigVo href="http://localhost:8080/common/view/{user/20190119/e1fe9925bc315c601b98eb1cb1349547719_1547866868179.jpg}">...</ConfigVo>
     */
    @GetMapping(value = "/download/**")
    public void download(HttpServletRequest request, HttpServletResponse response) {
        // ISO-8859-1 ==> UTF-8 进行编码转换
        String filePath = extractPathFromPattern(request);
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            filePath = filePath.replace("..", "");
            if (filePath.endsWith(",")) {
                filePath = filePath.substring(0, filePath.length() - 1);
            }
            String localPath = uploadpath;
            String downloadFilePath = localPath + File.separator + filePath;
            File file = new File(downloadFilePath);
            if (file.exists()) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                String a = file.getName();
                String[] strings = a.split("_");
                response.addHeader("Content-Disposition", "attachment;fileName="
                        + new String(strings[0].getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
                inputStream = new BufferedInputStream(Files.newInputStream(file.toPath()));
                // 用于app下载进度条显示
                response.setContentLengthLong(inputStream.available());
                outputStream = response.getOutputStream();
                byte[] buf = new byte[1024];
                int len;
                while ((len = inputStream.read(buf)) > 0) {
                    outputStream.write(buf, 0, len);
                }
                response.flushBuffer();
            }
        } catch (Exception e) {
            log.info("文件下载失败" + e.getMessage());
        } finally {
            closeStream(inputStream, outputStream);
        }
    }

    @PostMapping(value = "/uploadApk")
    public Result<?> uploadApk(HttpServletRequest request,
                               @RequestParam(name = "type", required = false) String type,
                               @RequestParam(name = "code", required = false) String code) {
        Result<?> result = new Result<>();
        FileOutputStream out = null;
        InputStream input = null;
        try {
            String ctxPath = uploadpath;
            String fileName;
            String bizPath = "files";
            String nowDay = new SimpleDateFormat("yyyyMMdd").format(new Date());
            File file;
            if (Strings.isNotBlank(type) && Strings.isNotBlank(code)) {
                file = new File(ctxPath + File.separator + bizPath + File.separator + nowDay + File.separator + type + File.separator + code);
            } else {
                file = new File(ctxPath + File.separator + bizPath + File.separator + nowDay + File.separator + "otherFile");
            }
            if (!file.exists()) {
                boolean r = file.mkdirs();
                if (!r) {
                    result.setMessage("创建文件根目录失败");
                    result.setSuccess(false);
                    return result;
                }
            }
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            MultipartFile mf = multipartRequest.getFile("file");
            if (mf == null) {
                result.setMessage("上传文件为空");
                result.setSuccess(false);
                return result;
            }
            // 获取文件名
            String orgName = mf.getOriginalFilename();
            if (orgName == null) {
                result.setMessage("获取文件名失败");
                result.setSuccess(false);
                return result;
            }
            String tempFileName = "tszygl" + random(8);// 设置上传后文件名
            fileName = tempFileName + orgName.substring(orgName.lastIndexOf("."));
            String savePath = file.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            input = mf.getInputStream();
            out = new FileOutputStream(savefile);
            IOUtils.copy(input, out);
            String dbpath;
            if (Strings.isNotBlank(type) && Strings.isNotBlank(code)) {
                dbpath = bizPath + File.separator + nowDay + File.separator
                        + type + File.separator + code + File.separator + fileName;
            } else {
                dbpath = bizPath + File.separator + nowDay + File.separator
                        + "otherFile" + File.separator + fileName;
            }
            if (dbpath.contains("\\")) {
                dbpath = dbpath.replace("\\", "/");
            }
            result.setMessage(dbpath);
            result.setSuccess(true);
        } catch (IOException e) {
            result.setSuccess(false);
            result.setMessage(e.getMessage());
            log.error(e.getMessage(), e);
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return result;
    }

    /**
     * pdf预览Iframe
     */
    @RequestMapping("/pdf/pdfPreviewIframe")
    public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
        modelAndView.setViewName("pdfPreviewIframe");
        return modelAndView;
    }

    /**
     * 把指定URL后的字符串全部截断当成参数
     * 这么做是为了防止URL中包含中文或者特殊字符（/等）时，匹配不了的问题
     */
    private static String extractPathFromPattern(final HttpServletRequest request) {
        String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
    }

    /**
     * 设置随机数
     *
     * @param bit 随机数的位数
     */
    public String random(int bit) {
        if (bit == 0) {
            bit = 6; // 默认6位
        }
        String str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";// 初始化种子
        char[] charArray = str.toCharArray();
        return RandomStringUtils.random(bit, 0, str.length(), false, false, charArray, new Random());
    }

    public static void main(String[] args) {
        CommonController commonController = new CommonController();
        System.out.println(commonController.random(10));
    }
    /**
     * 文件名作为参数传入
     *
     * @param fileName 文件名
     */
    @GetMapping(value = "/downloadWithFileName/**")
    public void downloadWithFileName(HttpServletRequest request, HttpServletResponse response, @RequestParam(name = "fileName") String fileName) {
        String filePath = extractPathFromPattern(request);
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            filePath = filePath.replace("..", "");
            if (filePath.endsWith(",")) {
                filePath = filePath.substring(0, filePath.length() - 1);
            }
            String localPath = uploadpath;
            String downloadFilePath = localPath + File.separator + filePath;
            File file = new File(downloadFilePath);
            if (file.exists()) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName="
                        + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
                inputStream = new BufferedInputStream(Files.newInputStream(file.toPath()));
                outputStream = response.getOutputStream();
                byte[] buf = new byte[1024];
                int len;
                while ((len = inputStream.read(buf)) > 0) {
                    outputStream.write(buf, 0, len);
                }
                response.flushBuffer();
            }
        } catch (Exception e) {
            log.error("文件下载失败{}", e.getMessage());
        } finally {
            closeStream(inputStream, outputStream);
        }
    }


}
